/**********************************************************************\

 Copyright 2012 Diggory Blake

 This file is part of klip-engine

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

\**********************************************************************/
#pragma once

class kMaterial;
class kImage;
class kEffect;

#include "kbase.h"
#include "kcommon.h"
#include "kmath.h"
#include "kerror.h"
#include "ksharedresources.h"

class kMaterial : public kBase, public kSharedResource<const kImage*> {
	friend class kSharedResourcesBase<kMaterial>;
	friend class kSharedResources<kMaterial>;
private:
	enum EParamType {
		EPT_Float,
		EPT_Integer
	};
	struct EffectParam {
		kHandle handle;
		union {
			float f[16];
			int i[16];
		};
		size_t num;
		EParamType type;
	};

	kEffect* _effect;
	const kImage* _textures[8];
	std::map<std::tstring, EffectParam> _params;

	static const bool AllowShare = false;
	static kSharedResources<kMaterial> _sharedMaterials;
	static kMaterial* createShared(Container* container, const Key& key);
	static void destroyShared(Container* container, kMaterial* resource);

public:
	kMaterial();
	inline kEffect* getEffect() const {
		return _effect;
	}
	inline const kImage* getTexture(size_t index = 0) const {
		if (index > 8) {
			throw kError(_T("Index out of bounds!"));
		}

		return _textures[index];
	}
	inline void setTexture(const kImage* texture, size_t index = 0) {
		if (index > 8) {
			throw kError(_T("Index out of bounds!"));
		}

		_textures[index] = texture;
	}
	void setEffect(kEffect* effect, bool clearParams = false);
	void setParam(const std::tstring& name, size_t n, const float* v);
	void setParam(const std::tstring& name, size_t n, const int* v);
	template<size_t N> inline void setParam(const std::tstring& name, const float (&v)[N]) {
		setParam(name, N, v);
	}
	template<size_t N> inline void setParam(const std::tstring& name, const int (&v)[N]) {
		setParam(name, N, v);
	}
	inline void setParam(const std::tstring& name, float v) {
		setParam(name, 1, &v);
	}
	inline void setParam(const std::tstring& name, int v) {
		setParam(name, 1, &v);
	}
	inline void unsetParam(const std::tstring& name) {
		_params.erase(name);
	}
	inline bool isParamSet(const std::tstring& name) const {
		return _params.find(name) != _params.end();
	}
	void begin() const;
	void end() const;

	static inline kSharedResources<kMaterial>* getShared() {
		return &_sharedMaterials;
	}
};
